package me.wangxuan.pat.controller;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringJoiner;
import java.util.logging.Logger;

import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import lombok.Data;
import me.wangxuan.pat.entity.Account;
import me.wangxuan.pat.entity.Api;
import me.wangxuan.pat.entity.Project;
import me.wangxuan.pat.generator.GeneratorFactory;
import me.wangxuan.pat.generator.GeneratorType;
import me.wangxuan.pat.processor.IHttpProcessor;
import me.wangxuan.pat.repository.AccountRepository;
import me.wangxuan.pat.repository.ApiRepository;
import me.wangxuan.pat.repository.ProjectRepository;
import me.wangxuan.pat.view.AccountManageDialog;
import me.wangxuan.pat.view.ApiManageDialog;
import me.wangxuan.pat.view.MainView;
import me.wangxuan.pat.view.ProjectManageDialog;
import me.wangxuan.pat.view.TwoButtonsEditor;
import me.wangxuan.pat.view.TwoButtonsRenderer;

@Data
public class MainController {
	private static final Logger logger = Logger.getLogger("global");
	private MainView mainView;
	private ProjectRepository projectRepo;
	private AccountRepository accountRepo;
	private ApiRepository apiRepo;

	public MainController(MainView view, ProjectRepository projectRepo, AccountRepository accountRepo,
			ApiRepository apiRepo) {
		this.mainView = view;
		this.projectRepo = projectRepo;
		this.accountRepo = accountRepo;
		this.apiRepo = apiRepo;

		mainView.getSendBtn().addActionListener(e -> {
			sendReq();
		});
		initParamsTableColumns(mainView.getParamsTable());

		mainView.getAddParamsBtn().addActionListener(e -> {
			addParamsRow();
		});
		initProjectBox();
		initProjectManager();
		initAccountBox();
		initAccountManager();
		initApiList();
		initApiManager();
	}

	private void initApiList() {
		DefaultComboBoxModel<Project> boxModel = (DefaultComboBoxModel<Project>) mainView.getProjectBox().getModel();
		Project selectedP = (Project) boxModel.getSelectedItem();
		List<Api> apis = new ArrayList<>();
		if (selectedP != null) {
			apis = apiRepo.findByNativeSql("select a.* from t_pat_api a where a.project_id = ?1",
					selectedP.getProjectId());
		}
		JList<Api> apiList = mainView.getApilist();
		Api selectedApi = mainView.getApilist().getSelectedValue();

		DefaultListModel<Api> listModel = (DefaultListModel<Api>) mainView.getApilist().getModel();
		listModel.removeAllElements();
		for (Api a : apis) {
			listModel.addElement(a);
			if (selectedApi != null && selectedApi.getApiId().equals(a.getApiId())) {
				mainView.getApilist().setSelectedValue(a, true);
			}
		}

		// 添加双击事件监听器
		apiList.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					Api selectedApi = apiList.getSelectedValue();
					if (selectedApi != null) {
						System.out.println("Double click: " + selectedApi);
						DefaultComboBoxModel<Project> boxModel = (DefaultComboBoxModel<Project>) mainView
								.getProjectBox().getModel();
						Project p = (Project) boxModel.getSelectedItem();

						DefaultComboBoxModel<Account> aboxModel = (DefaultComboBoxModel<Account>) mainView
								.getAccountBox().getModel();

						Account a = (Account) aboxModel.getSelectedItem();
						fillMainPane(p, a, selectedApi);
					}
				}
			}
		});
	}

	protected void fillMainPane(Project selectedP, Account account, Api selectedApi) {
		mainView.getMethodBox().setSelectedItem(selectedApi.getMethod());
		mainView.getContentTypeBox().setSelectedItem(selectedApi.getContentType());
		mainView.getUrlField().setText(account.getDomain() + selectedApi.getUrl());
		DefaultTableModel tModel = mainView.getTableModel();
		// 清空 参数列表
		tModel.setRowCount(0);
//		logger.info("tModel.getRowCount():"+tModel.getRowCount());
//		int rowCount = tModel.getRowCount();
//		for (int rowCnt = rowCount - 1; rowCnt >= 0; rowCnt--) {
//		    tModel.removeRow(rowCnt);
//		}
//		logger.info("tModel.getRowCount() after remove:"+tModel.getRowCount());
		JSONObject accountCfg = new JSONObject();
		if (JSON.isValidObject(account.getConfigs())) {
			accountCfg = JSON.parseObject(account.getConfigs());
		}
		logger.info("ApiCommonParams:" + selectedP.getApiCommonParams());
		if (JSON.isValidArray(selectedP.getApiCommonParams())) {
			JSONArray array = JSON.parseArray(selectedP.getApiCommonParams());
			logger.info("ApiCommonParams:" + array);
			for (int i = 0; i < array.size(); i++) {
				JSONObject o = array.getJSONObject(i);
				Object[] newRow = { o.getString("name"), accountCfg.getString(o.getString("name")) == null ? ""
						: accountCfg.getString(o.getString("name")), GeneratorType.timestamp, "生成" };
				tModel.addRow(newRow);
			}
		}

		if (JSON.isValidArray(selectedApi.getParams())) {
			JSONArray array = JSON.parseArray(selectedApi.getParams());
			for (int i = 0; i < array.size(); i++) {
				JSONObject o = array.getJSONObject(i);
				Object[] newRow = { o.getString("name"), "", GeneratorType.timestamp, "生成" };
				tModel.addRow(newRow);
			}
		}

	}

	private void initApiManager() {
		mainView.getApiBtn().addActionListener(e -> {
			List<Project> projects = projectRepo.findAll();
			List<Api> apis = apiRepo.findAll();
			ApiManageDialog apiDialog = new ApiManageDialog(mainView, apis, projects);
			apiDialog.getAddButton().addActionListener(ae -> {
				me.wangxuan.pat.view.ApiManageDialog.AddRecordForm addForm = apiDialog.new AddRecordForm(
						(JFrame) apiDialog.getOwner(), projects, null);
				addForm.setVisible(true);

				Api a = addForm.getRecord();
				if (a != null) {
					apiRepo.save(a);
					apiDialog.getRecords().add(a);
					apiDialog.getTableModel().addRow(new Object[] { a.getApiId(), a.getApiName(),
							a.getProject().getProjectName(), a.getUrl(), a.getParams() });
					initApiList();
				}
			});
			apiDialog.getUpdateButton().addActionListener(ae -> {
				// 获取选中的行
				int selectedRow = apiDialog.getRecordTable().getSelectedRow();
				if (selectedRow != -1) {
					Api a = apiDialog.getRecords().get(selectedRow);
					me.wangxuan.pat.view.ApiManageDialog.AddRecordForm addForm = apiDialog.new AddRecordForm(
							(JFrame) apiDialog.getOwner(), projects, a);
					addForm.setVisible(true);
					// 获取用户输入的记录
					a = addForm.getRecord();
					try {
						apiRepo.save(a);
						// 从表格和列表中删除选中的记录 "接口ID", "接口名称", "所属项目", "接口地址", "参数配置"
						apiDialog.getTableModel().setValueAt(a.getApiName(), selectedRow, 1);
						apiDialog.getTableModel().setValueAt(a.getProject().getProjectName(), selectedRow, 2);
						apiDialog.getTableModel().setValueAt(a.getUrl(), selectedRow, 3);
						apiDialog.getTableModel().setValueAt(a.getParams(), selectedRow, 4);
						initApiList();
					} catch (Exception ex) {
						JOptionPane.showMessageDialog(apiDialog, "修改失败！\n" + ex.getMessage());
					}
				} else {
					JOptionPane.showMessageDialog(apiDialog, "请先选择要修改的记录！");
				}
			});
			apiDialog.getDeleteButton().addActionListener(ae -> {
				// 获取选中的行
				int selectedRow = apiDialog.getRecordTable().getSelectedRow();
				if (selectedRow != -1) {
					Api a = apiDialog.getRecords().get(selectedRow);
					apiRepo.deleteById(a.getApiId());
					// 从表格和列表中删除选中的记录
					apiDialog.getTableModel().removeRow(selectedRow);
					apiDialog.getRecords().remove(selectedRow);
					initApiList();
				} else {
					JOptionPane.showMessageDialog(apiDialog, "请先选择要删除的记录！");
				}
			});

			apiDialog.setVisible(true);
		});
	}

	private void initAccountBox() {
		DefaultComboBoxModel<Project> boxModel = (DefaultComboBoxModel<Project>) mainView.getProjectBox().getModel();
		Project selectedP = (Project) boxModel.getSelectedItem();

		DefaultComboBoxModel<Account> accountBoxModel = (DefaultComboBoxModel<Account>) mainView.getAccountBox()
				.getModel();
		Account selectedA = (Account) accountBoxModel.getSelectedItem();
		List<Account> accounts = new ArrayList<>();
		if (selectedP != null) {
			accounts = accountRepo.findByNativeSql("select a.* from t_pat_account a where a.project_id = ?1",
					selectedP.getProjectId());
		}

		accountBoxModel.removeAllElements();
		for (Account a : accounts) {
			accountBoxModel.addElement(a);
			if (selectedA != null && a.getAccountId().equals(selectedA.getAccountId())) {
				accountBoxModel.setSelectedItem(a);
			}
		}
		logger.info("getDomain:" + ((Account) accountBoxModel.getSelectedItem()).getDomain());
		;
	}

	private void initAccountManager() {
		mainView.getAccountBtn().addActionListener(e -> {
			List<Project> projects = projectRepo.findAll();
			List<Account> accounts = accountRepo.findAll();
			AccountManageDialog accountDialog = new AccountManageDialog(mainView, accounts, projects);
			accountDialog.getAddButton().addActionListener(ae -> {
				me.wangxuan.pat.view.AccountManageDialog.AddRecordForm addForm = accountDialog.new AddRecordForm(
						(JFrame) accountDialog.getOwner(), projects, null);
				addForm.setVisible(true);

				Account a = addForm.getRecord();
				if (a != null) {
					accountRepo.save(a);
					accountDialog.getRecords().add(a);
					accountDialog.getTableModel().addRow(new Object[] { a.getAccountId(), a.getAccountName(),
							a.getProject().getProjectName(), a.getDomain(), a.getConfigs() });
					initAccountBox();
				}
			});
			accountDialog.getUpdateButton().addActionListener(ae -> {
				// 获取选中的行
				int selectedRow = accountDialog.getRecordTable().getSelectedRow();
				if (selectedRow != -1) {
					Account a = accountDialog.getRecords().get(selectedRow);
					me.wangxuan.pat.view.AccountManageDialog.AddRecordForm addForm = accountDialog.new AddRecordForm(
							(JFrame) accountDialog.getOwner(), projects, a);
					addForm.setVisible(true);
					// 获取用户输入的记录
					a = addForm.getRecord();
					try {
						accountRepo.save(a);
						// 从表格和列表中删除选中的记录 "账号ID", "账号名称", "所属项目", "接口域名", "账号配置"
						accountDialog.getTableModel().setValueAt(a.getAccountName(), selectedRow, 1);
						accountDialog.getTableModel().setValueAt(a.getProject().getProjectName(), selectedRow, 2);
						accountDialog.getTableModel().setValueAt(a.getDomain(), selectedRow, 3);
						accountDialog.getTableModel().setValueAt(a.getConfigs(), selectedRow, 4);
						initAccountBox();
					} catch (Exception ex) {
						JOptionPane.showMessageDialog(accountDialog, "修改失败！\n" + ex.getMessage());
					}
				} else {
					JOptionPane.showMessageDialog(accountDialog, "请先选择要修改的记录！");
				}
			});
			accountDialog.getDeleteButton().addActionListener(ae -> {
				// 获取选中的行
				int selectedRow = accountDialog.getRecordTable().getSelectedRow();
				if (selectedRow != -1) {
					Account a = accountDialog.getRecords().get(selectedRow);
					accountRepo.deleteById(a.getAccountId());
					// 从表格和列表中删除选中的记录
					accountDialog.getTableModel().removeRow(selectedRow);
					accountDialog.getRecords().remove(selectedRow);
					initProjectBox();
				} else {
					JOptionPane.showMessageDialog(accountDialog, "请先选择要删除的记录！");
				}
			});

			accountDialog.setVisible(true);
		});
	}

	private void initProjectBox() {
		List<Project> projects = projectRepo.findAll();
		DefaultComboBoxModel<Project> boxModel = (DefaultComboBoxModel<Project>) mainView.getProjectBox().getModel();
		Project selectedP = (Project) boxModel.getSelectedItem();
		boxModel.removeAllElements();
		for (Project p : projects) {
			boxModel.addElement(p);
			if (selectedP != null && p.getProjectId().equals(selectedP.getProjectId())) {
				boxModel.setSelectedItem(p);
			}
		}
	}

	private void initProjectManager() {

		mainView.getProjectBtn().addActionListener(e -> {
			// 项目管理对话框
			List<Project> list = projectRepo.findAll();
			ProjectManageDialog projectDialog = new ProjectManageDialog(mainView, list);
			projectDialog.getAddButton().addActionListener(ae -> {
				me.wangxuan.pat.view.ProjectManageDialog.AddRecordForm addForm = projectDialog.new AddRecordForm(
						(JFrame) projectDialog.getOwner(), null);
				addForm.setVisible(true);
				// 获取用户输入的记录
				Project newRecord = addForm.getRecord();
				// 创建新记录并添加到列表和表格中
				if (newRecord != null) {
					projectRepo.save(newRecord);
					projectDialog.getRecords().add(newRecord);
					projectDialog.getTableModel()
							.addRow(new Object[] { newRecord.getProjectId(), newRecord.getProjectName(),
									newRecord.getAccountConfigs(), newRecord.getApiCommonParams(),
									newRecord.getProcessor() });
					initProjectBox();
				}
			});
			projectDialog.getUpdateButton().addActionListener(ae -> {
				// 获取选中的行
				int selectedRow = projectDialog.getRecordTable().getSelectedRow();
				if (selectedRow != -1) {
					Project p = projectDialog.getRecords().get(selectedRow);
					me.wangxuan.pat.view.ProjectManageDialog.AddRecordForm addForm = projectDialog.new AddRecordForm(
							(JFrame) projectDialog.getOwner(), p);
					addForm.setVisible(true);
					// 获取用户输入的记录
					p = addForm.getRecord();
					try {
						projectRepo.save(p);
						// 从表格和列表中删除选中的记录
						projectDialog.getTableModel().setValueAt(p.getProjectName(), selectedRow, 1);
						projectDialog.getTableModel().setValueAt(p.getAccountConfigs(), selectedRow, 2);
						projectDialog.getTableModel().setValueAt(p.getApiCommonParams(), selectedRow, 3);
						projectDialog.getTableModel().setValueAt(p.getProcessor(), selectedRow, 4);
						initProjectBox();
					} catch (Exception ex) {
						JOptionPane.showMessageDialog(projectDialog, "修改失败！\n" + ex.getMessage());
					}
				} else {
					JOptionPane.showMessageDialog(projectDialog, "请先选择要修改的记录！");
				}
			});
			projectDialog.getDeleteButton().addActionListener(ae -> {
				// 获取选中的行
				int selectedRow = projectDialog.getRecordTable().getSelectedRow();
				if (selectedRow != -1) {
					Project p = projectDialog.getRecords().get(selectedRow);
					projectRepo.deleteById(p.getProjectId());
					// 从表格和列表中删除选中的记录
					projectDialog.getTableModel().removeRow(selectedRow);
					projectDialog.getRecords().remove(selectedRow);
					initProjectBox();
				} else {
					JOptionPane.showMessageDialog(projectDialog, "请先选择要删除的记录！");
				}
			});

			projectDialog.setVisible(true);
		});
	}

	private void initParamsTableColumns(JTable table) {
		table.setShowGrid(true); // 显示网格线
		TableColumnModel colModel = table.getColumnModel();
		colModel.getColumn(0).setCellEditor(new DefaultCellEditor(new JTextField()));
		colModel.getColumn(1).setCellEditor(new DefaultCellEditor(new JTextField()));

//		table.getColumnModel().getColumn(2).setPreferredWidth(200);

		// Dropdown column
		JComboBox<GeneratorType> comboBox = new JComboBox<>(
				new GeneratorType[] { GeneratorType.timestamp, GeneratorType.idCard });
		TableColumn typeCol = colModel.getColumn(2);
		typeCol.setCellRenderer(new DefaultTableCellRenderer());
		typeCol.setCellEditor(new DefaultCellEditor(comboBox));

		// Button column
		TableColumn opCol = colModel.getColumn(3);
		TwoButtonsRenderer buttonRender = new TwoButtonsRenderer(table);
		opCol.setCellRenderer(buttonRender);
		opCol.setCellEditor(new TwoButtonsEditor(table, e -> {
			JButton source = (JButton) e.getSource();
			int row = (int) source.getClientProperty("row");
//			System.out.println(e.getSource());
			logger.info("row:" + row);
			DefaultTableModel tModel = mainView.getTableModel();

			GeneratorType gt = (GeneratorType) tModel.getValueAt(row, 2);
			logger.info("code:" + gt.getCode() + " name:" + gt.getName());
//					System.out.println(GeneratorFactory.createGenerator(gt));
			tModel.setValueAt(GeneratorFactory.createGenerator(gt).generate(), row, 1);
		}, e -> {
			JButton source = (JButton) e.getSource();
			int row = (int) source.getClientProperty("row");
			logger.info("row:" + row);
			DefaultTableModel tModel = mainView.getTableModel();
			logger.info("rowCount:" + tModel.getRowCount());
			logger.info("table.isEditing:" + table.isEditing());
			if (table.isEditing()) {
				table.getCellEditor().stopCellEditing();
			}
			tModel.removeRow(row);

		}));
	}

	private void addParamsRow() {
		Object[] newRow = { "", "", GeneratorType.timestamp, "生成" };
		mainView.getTableModel().addRow(newRow);
	}

	private void sendReq() {
		DefaultComboBoxModel<Project> boxModel = (DefaultComboBoxModel<Project>) mainView.getProjectBox().getModel();
		Project selectedP = (Project) boxModel.getSelectedItem();

		DefaultComboBoxModel<Account> aboxModel = (DefaultComboBoxModel<Account>) mainView.getAccountBox().getModel();
		Account account = (Account) aboxModel.getSelectedItem();
		logger.info("domain:" + account.getDomain());
		String method = (String) mainView.getMethodBox().getSelectedItem();
		String contentType = (String) mainView.getContentTypeBox().getSelectedItem();
		String url = mainView.getUrlField().getText();
		Boolean useProcessor = mainView.getProcessorCheck().isSelected();
		logger.info("url: " + url + " method:" + method);
		DefaultTableModel tModel = mainView.getTableModel();
		int rowCnt = tModel.getRowCount();
		// int colCnt = tModel.getColumnCount();
		Map<String, Object> params = new HashMap<>();
		for (int i = 0; i < rowCnt; i++) {
			// logger.info("key:" + tModel.getValueAt(i, 0) + " value:" +
			// tModel.getValueAt(i, 1));
			if(StrUtil.isNotBlank((String) tModel.getValueAt(i, 0)) && StrUtil.isNotBlank((String) tModel.getValueAt(i, 1))) {
				params.put((String) tModel.getValueAt(i, 0), tModel.getValueAt(i, 1));
			}
		}
		String result = "";
		if ("GET".equals(method)) {
			// 创建 GET 请求
			HttpRequest request = HttpUtil.createGet(url);
			// 设置连接超时时间为 5000 毫秒
			request.setReadTimeout(5000);
			// 添加请求头
			request.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
			// 发送请求并获取响应
			HttpResponse response = request.execute();
			// 获取响应状态码和内容
			int statusCode = response.getStatus();
			result = response.body();

			logger.info("Response Code: " + statusCode);
			logger.info("Response Body: " + result);
		} else if ("POST".equals(method)) {
			String json = buildParamsStr(contentType, params, useProcessor, selectedP, account);
			logger.info("request url:" + url);
			logger.info("request params:" + json);
			// 创建 POST 请求
			HttpRequest request = HttpUtil.createPost(url).header("Content-Type", contentType).body(json);
			// 发送请求并获取响应
			HttpResponse response = request.execute();
			// 获取响应状态码和内容
			int statusCode = response.getStatus();
			result = response.body();
			logger.info("Response Code: " + statusCode);
			logger.info("Response Body: " + result);
		}

		StyledDocument doc = mainView.getRespPane().getStyledDocument();
		try {
			doc.insertString(doc.getLength(), result + "\n", null);
//			doc.insertString(rowCnt, result, null);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}

	private IHttpProcessor getProcessor(Project p) {
		String processorCls = p.getProcessor();
		if (StrUtil.isNotBlank(processorCls)) {
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			try {
				IHttpProcessor processor = (IHttpProcessor) classLoader.loadClass(processorCls).getDeclaredConstructor()
						.newInstance();
				return processor;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	private String buildParamsStr(String contentType, Map<String, Object> params, boolean useProcessor, Project p,
			Account a) {
		String str = "";
		if (useProcessor) {
			IHttpProcessor processor = getProcessor(p);
			if (processor != null) {
				processor.buildReqParams(params, a);
			}
		}

		if (ContentType.JSON.getValue().equals(contentType)) {
			str = JSON.toJSONString(params);
		} else {
			StringJoiner joiner = new StringJoiner("&");
			for (Entry<String, Object> entry : params.entrySet()) {
				joiner.add(entry.getKey() + "=" + entry.getValue());// 要不要做UrlEncode
			}
			str = joiner.toString();
		}

		return str;
	}

	public void showView() {
		mainView.setVisible(true);
	}
}
